const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const userSchema = new mongoose.Schema({
  tenantId: {
    type: String,
    required: true,
    index: true
  },
  email: {
    type: String,
    required: true,
    lowercase: true,
    trim: true,
    match: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
  },
  password: {
    type: String,
    required: true,
    minlength: 6
  },
  firstName: {
    type: String,
    required: true,
    trim: true,
    maxlength: 50
  },
  lastName: {
    type: String,
    required: true,
    trim: true,
    maxlength: 50
  },
  role: {
    type: String,
    enum: ['admin', 'manager', 'user', 'viewer'],
    default: 'user'
  },
  status: {
    type: String,
    enum: ['active', 'inactive', 'pending', 'suspended'],
    default: 'pending'
  },
  profile: {
    avatar: {
      type: String,
      default: null
    },
    phone: {
      type: String,
      default: null
    },
    timezone: {
      type: String,
      default: 'UTC'
    },
    language: {
      type: String,
      default: 'en'
    },
    bio: {
      type: String,
      maxlength: 500,
      default: ''
    }
  },
  preferences: {
    theme: {
      type: String,
      enum: ['light', 'dark', 'auto'],
      default: 'light'
    },
    notifications: {
      email: {
        type: Boolean,
        default: true
      },
      push: {
        type: Boolean,
        default: true
      },
      sms: {
        type: Boolean,
        default: false
      }
    },
    privacy: {
      profileVisible: {
        type: Boolean,
        default: true
      },
      activityVisible: {
        type: Boolean,
        default: true
      }
    }
  },
  security: {
    emailVerified: {
      type: Boolean,
      default: false
    },
    emailVerificationToken: {
      type: String,
      default: null
    },
    passwordResetToken: {
      type: String,
      default: null
    },
    passwordResetExpires: {
      type: Date,
      default: null
    },
    twoFactorEnabled: {
      type: Boolean,
      default: false
    },
    twoFactorSecret: {
      type: String,
      default: null
    },
    lastLogin: {
      type: Date,
      default: null
    },
    loginAttempts: {
      type: Number,
      default: 0
    },
    lockUntil: {
      type: Date,
      default: null
    }
  },
  permissions: [{
    resource: {
      type: String,
      required: true
    },
    actions: [{
      type: String,
      enum: ['create', 'read', 'update', 'delete', 'manage']
    }]
  }],
  metadata: {
    type: Map,
    of: mongoose.Schema.Types.Mixed,
    default: new Map()
  }
}, {
  timestamps: true,
  toJSON: { 
    virtuals: true,
    transform: function(doc, ret) {
      delete ret.password;
      delete ret.security.passwordResetToken;
      delete ret.security.twoFactorSecret;
      delete ret.__v;
      return ret;
    }
  },
  toObject: { virtuals: true }
});

// 复合索引：租户ID + 邮箱唯一
userSchema.index({ tenantId: 1, email: 1 }, { unique: true });
userSchema.index({ tenantId: 1, role: 1 });
userSchema.index({ tenantId: 1, status: 1 });
userSchema.index({ 'security.emailVerificationToken': 1 });
userSchema.index({ 'security.passwordResetToken': 1 });

// 虚拟字段：全名
userSchema.virtual('fullName').get(function() {
  return `${this.firstName} ${this.lastName}`;
});

// 虚拟字段：是否被锁定
userSchema.virtual('isLocked').get(function() {
  return !!(this.security.lockUntil && this.security.lockUntil > Date.now());
});

// 虚拟字段：是否为管理员
userSchema.virtual('isAdmin').get(function() {
  return this.role === 'admin';
});

// 虚拟字段：是否活跃
userSchema.virtual('isActive').get(function() {
  return this.status === 'active';
});

// 静态方法：根据租户ID和邮箱查找用户
userSchema.statics.findByTenantAndEmail = function(tenantId, email) {
  return this.findOne({ 
    tenantId, 
    email: email.toLowerCase() 
  });
};

// 静态方法：根据租户ID获取用户列表
userSchema.statics.findByTenant = function(tenantId, options = {}) {
  const query = { tenantId };
  
  if (options.status) {
    query.status = options.status;
  }
  
  if (options.role) {
    query.role = options.role;
  }
  
  return this.find(query)
    .sort(options.sort || { createdAt: -1 })
    .limit(options.limit || 50)
    .skip(options.skip || 0);
};

// 静态方法：根据邮箱验证令牌查找
userSchema.statics.findByEmailVerificationToken = function(token) {
  return this.findOne({ 'security.emailVerificationToken': token });
};

// 静态方法：根据密码重置令牌查找
userSchema.statics.findByPasswordResetToken = function(token) {
  return this.findOne({ 
    'security.passwordResetToken': token,
    'security.passwordResetExpires': { $gt: Date.now() }
  });
};

// 实例方法：验证密码
userSchema.methods.comparePassword = async function(candidatePassword) {
  return bcrypt.compare(candidatePassword, this.password);
};

// 实例方法：设置密码
userSchema.methods.setPassword = async function(password) {
  const saltRounds = parseInt(process.env.BCRYPT_ROUNDS) || 12;
  this.password = await bcrypt.hash(password, saltRounds);
  return this;
};

// 实例方法：生成邮箱验证令牌
userSchema.methods.generateEmailVerificationToken = function() {
  const crypto = require('crypto');
  const token = crypto.randomBytes(32).toString('hex');
  this.security.emailVerificationToken = token;
  return token;
};

// 实例方法：验证邮箱
userSchema.methods.verifyEmail = function() {
  this.security.emailVerified = true;
  this.security.emailVerificationToken = null;
  if (this.status === 'pending') {
    this.status = 'active';
  }
  return this.save();
};

// 实例方法：生成密码重置令牌
userSchema.methods.generatePasswordResetToken = function() {
  const crypto = require('crypto');
  const token = crypto.randomBytes(32).toString('hex');
  this.security.passwordResetToken = token;
  this.security.passwordResetExpires = Date.now() + 3600000; // 1小时后过期
  return token;
};

// 实例方法：重置密码
userSchema.methods.resetPassword = async function(newPassword) {
  await this.setPassword(newPassword);
  this.security.passwordResetToken = null;
  this.security.passwordResetExpires = null;
  this.security.loginAttempts = 0;
  this.security.lockUntil = null;
  return this.save();
};

// 实例方法：记录登录
userSchema.methods.recordLogin = function() {
  this.security.lastLogin = new Date();
  this.security.loginAttempts = 0;
  this.security.lockUntil = null;
  return this.save();
};

// 实例方法：增加登录尝试次数
userSchema.methods.incLoginAttempts = function() {
  // 如果之前有锁定且已过期，重置计数器
  if (this.security.lockUntil && this.security.lockUntil < Date.now()) {
    return this.updateOne({
      $unset: { 'security.lockUntil': 1 },
      $set: { 'security.loginAttempts': 1 }
    });
  }
  
  const updates = { $inc: { 'security.loginAttempts': 1 } };
  
  // 如果达到最大尝试次数且当前未锁定，则锁定账户
  const maxAttempts = 5;
  const lockTime = 2 * 60 * 60 * 1000; // 2小时
  
  if (this.security.loginAttempts + 1 >= maxAttempts && !this.isLocked) {
    updates.$set = { 'security.lockUntil': Date.now() + lockTime };
  }
  
  return this.updateOne(updates);
};

// 实例方法：检查权限
userSchema.methods.hasPermission = function(resource, action) {
  // 管理员拥有所有权限
  if (this.role === 'admin') {
    return true;
  }
  
  const permission = this.permissions.find(p => p.resource === resource);
  if (!permission) {
    return false;
  }
  
  return permission.actions.includes(action) || permission.actions.includes('manage');
};

// 实例方法：添加权限
userSchema.methods.addPermission = function(resource, actions) {
  const existingPermission = this.permissions.find(p => p.resource === resource);
  
  if (existingPermission) {
    // 合并权限
    const newActions = [...new Set([...existingPermission.actions, ...actions])];
    existingPermission.actions = newActions;
  } else {
    this.permissions.push({ resource, actions });
  }
  
  return this.save();
};

// 实例方法：移除权限
userSchema.methods.removePermission = function(resource, actions = null) {
  if (actions === null) {
    // 移除整个资源的权限
    this.permissions = this.permissions.filter(p => p.resource !== resource);
  } else {
    // 移除特定操作的权限
    const permission = this.permissions.find(p => p.resource === resource);
    if (permission) {
      permission.actions = permission.actions.filter(a => !actions.includes(a));
      if (permission.actions.length === 0) {
        this.permissions = this.permissions.filter(p => p.resource !== resource);
      }
    }
  }
  
  return this.save();
};

// 中间件：保存前哈希密码
userSchema.pre('save', async function(next) {
  // 只有密码被修改时才重新哈希
  if (!this.isModified('password')) {
    return next();
  }
  
  try {
    const saltRounds = parseInt(process.env.BCRYPT_ROUNDS) || 12;
    this.password = await bcrypt.hash(this.password, saltRounds);
    next();
  } catch (error) {
    next(error);
  }
});

// 中间件：保存前验证邮箱在租户内唯一
userSchema.pre('save', async function(next) {
  if (!this.isModified('email') && !this.isNew) {
    return next();
  }
  
  try {
    const existingUser = await this.constructor.findOne({
      tenantId: this.tenantId,
      email: this.email,
      _id: { $ne: this._id }
    });
    
    if (existingUser) {
      const error = new Error('Email already exists in this tenant');
      error.code = 'DUPLICATE_EMAIL';
      return next(error);
    }
    
    next();
  } catch (error) {
    next(error);
  }
});

const User = mongoose.model('User', userSchema);

module.exports = User;